查看原文
其他

细节、标准与沟通——一名前端的混合开发经验

严选技术 严选技术产品团队 2023-03-31





在严选基于webview+APP的混合开发模式下,前端和客户端的协作显得尤为重要。细节、标准与沟通可以说是我过去两年时间做混合开发的主要经验,本文中将从这几个方面展开,来从一个前端的角度讲述混合开发经验。




1. 概述
过去几年混合开发的风向变了又变,然而无论是weex、rn还是flutter,都没有成为严选的最终选择。目前我们的混合开发仍然是webview+APP的形式,由前端和客户端协作完成。
作为一名前端,我在过去一年多的时间里,负责了jsbridge标准化建设,并在22年下半年负责推进了严选iOS端离线包能力的重建和落地。这里将我在混合开发中积累的一些经验做一些总结,希望能对相关同学有些许帮助。想讲的内容主要分三部分:
  • 正式职能gap,注重细节:讲述我所认识到的,前端和客户端开发之间存在的gap,导致的问题以及如何解决。
  • 重视标准建设,不以规矩,后患无穷:从严选的“黑历史”开始讲起,看看缺乏标准带来的问题,以及如何建立有效的混合开发标准。
  • 沟通和理解是永远是合作的不二法则:要沟通、要理解,前端和客户端都是开发,需要更多的沟通和理解,这样才能在混合开发的路上共同越走越远。

2. 正视职能gap,注重细节

2.1 职能gap有哪些

很容易想到的是:前端和客户端之间的gap。但是还存在的是:安卓开发和iOS开发之间的gap。
  • 前端和客户端之间的gap


    • 专业知识带来的gap:你们前端发请求不需要手动带cookie的吗?


    • 业务逻辑带来的gap:我们统一调底层方法去发请求的,具体逻辑要问xxx。


    • 旧代码-祖传gap:我们以前一直这样搞的,没改过。


  • 安卓开发和iOS开发之间的gap


    • 系统带来的gap:你们iOS不能直接下载文件的吗,安卓都不限制的啊。


    • 框架带来的gap:这个不行啊,我们用的那个框架限制死了,改不了。


2.2 职能gap会带来什么问题,怎么克服?
前端和客户端之间的gap容易导致逻辑是黑盒,从而可能忽略一些关键点,导致最终产出的结果出现偏差。一般人都不会认为自己常用的能力存在问题。
安卓开发和iOS开发之间的gap则容易导致两端能力最终表现不一致,因为框架和系统层面的内容在开发理解中都是理所当然、无法变更的,所以如果不主动发现,可能不一定能暴露出来问题。
两种gap其实都是认知上的gap,所以如果要减少其影响,就要更多注重细节,把黑盒内容展开来看,如:
  • 你们底层方法大概是个啥逻辑,干了些啥事情?
  • 看下你们旧代码是怎么搞的,具体流程是啥?
  • 这个处理你们两端分别是怎么样的?
2.3 细节到什么程度?
  • 细到表现层


  • 这个比较好理解,以一个jsbridge调用为例,就是调用之后的表现。比如设定日历提醒,在权限控制上,可以有以下细节:
    • 在没有权限的时候,是否会弹出授权弹窗?


    • 如果用户已经禁止了日历权限,如何表现?


    • 如果用户已经授权了,如何表现?


    • 如果用户先给了授权,然后又手动关闭授权,如何表现?


    • 如果用户先禁止授权,然后又手动开启授权,如何表现?


最后两个其实一般来说属于qa测试的范畴了,不太归属于正常的case,这里也只是简单给个例子。对于前端来说,当然是能注意到越多的表现层case越好,毕竟如果能在联调阶段就解决了问题,那测试阶段的问题就会少一些。
  • 细到工作流程


如果是一个比较复杂的能力,其必然是存在各个模块直接的流程串联的,所谓细到流程,就是深入了解每一步流程的执行逻辑。这里以严选的离线包工作流程的部分内容为例:
以这里的请求离线配置表为例,就会有以下的细节可以考虑:
    • 请求的配置是哪个地址?


    • 请求的时机和频率?


    • 请求失败了怎么做?


是否有更新又可以提出:
    • 怎么判断是否更新?


    • 如果只有配置表的版本号更新,算不算更新?


    • 如果只有单个资源的版本号更新,算不算更新,后续的资源下载会涉及哪些资源的更新?


实际情况可能不一定要考虑的那么细,但是基于上文提到的“职能gap”,某些流程对客户端而言可能是:按照通常的处理方式来处理A,然后调用公用方法库来处理B,最后C这里就维持原来的处理逻辑,等等。这些对于前端来说都是黑盒。而这样一些功能,其最终的使用者主要还是前端,了解清楚细节,才能保证最终的功能更好符合前端的预期。
  • 细到异常处理


异常处理影响功能的健壮性,处理好异常的能力才能经受线上用户的考验。
    • 输入异常时,是否能做到一定的兼容处理;


    • 执行异常时,是否能抛出错误,或者上报错误;


    • 执行异常时,是否有一定的挽留措施;


    • 大面积执行异常时,能否有及时止损的手段。


大到跨多模块多进程的能力,小到输入a输出b的jsbridge,都应当考虑异常处理。设计阶段不好好考虑,那么后续要么是前端额外做兜底,要么是前端增加版本兼容——总之前端都会是受害者之一。

3. 重视标准建设,不以规矩,后患无穷

身为前端,客户端内部的标准当然主要还是客户端同事去建设。但是一旦涉及前端的,就应当积极协同客户端同时定好标准,否则功能一旦做出来上线了,因为客户端的历史版本和更新率等问题,前端就会很难受。
3.1 严选jsbridge的“黑历史”
在业务快速扩展的年代,由于需求多且杂,主要以满足业务需求为主要目的,严选的jsbridge呈现出一些问题:
  • api标准不统一,命名、调用方式等差异较大,返回值格式也有所不同;


  • 容易出现数个功能相近的jsbridge,造成冗余;


  • 两端表现不一致,前端必须分开兼容。


这些问题由于客户端存在历史版本问题,本身不好再变更jsbridge能力,因此也给前端同学带来了一定的负担。
3.2 “黑历史”问题的治理
事实上,目前也并不能说是100%解决了黑历史中的问题,但是目前我们的前端开发在业务开发中,相比之前需要了解到的各种jsbridge相关的“奇技淫巧”要少了很多,大多数情况只要直接调用即可。目前主要的解决手段有两个:SDK抹平差异健全说明文档
  • SDK抹平差异


对存量的100+ jsbridge api,每个进行筛选,剔出要额外抹平差异的部分并进行兼容。SDK中,主要做的抹平差异的事情有:
    • 所有方法封装成支持回调和promise方式调用,对于原来要通过方法+事件监听调用的,则进行拼装。
    /* before */window.NEJsbridge.call('setShareToSNSCallback', {}); // 唤起分享面板window.onShareResult = (res) => { // 处理分享完成}
    /* now */invoke('setShareToSNSCallback', {}).then(([res]) => { // 处理分享完成})
    • 通过对存在端差异每个api分别hack的方式,抹平其中的差异。


/* before */// 获取环境信息if (os.isIos) { appInfo = window.WebViewJavascriptBridge && window.WebViewJavascriptBridge.appInfo} else { // 注入时间问题,获取太早可能拿不到 const cb = window.NEJsbridge.invoke('appInfo', {}, function(res) { appInfo = res; });
if (window.NEJsbridge) { cb(); } else { document.addEventListener('NEJsbridgeReady', cb, false); }}
/* now */invoke('appInfo').then(([res]) => { appInfo = res;})
    • 对少量api设计的有问题的,重新调整其调用方式,统一调用体验。


/* before */const cb = window.NEJsbridge.beforeExitWebView = () => { // 拦截左上角返回按钮退出 return true;};
if (window.NEJsbridge) { cb();} else { document.addEventListener('NEJsbridgeReady', cb, false);}
/* now */invoke('beforeExitWebView', {}, function () { return true;});
  • 健全说明文档


我们重新整理了所有的api,按照统一的格式说明其出参入参,对于调用时需要注意的,额外列出注明。同时给api增加了demo示例,可以直接扫码查看。目前严选所有前端&客户端开发均统一参考该文档。

展开后,demo的源码也可以直接看到:

3.3 定什么标准,怎么保证执行?

  • 最重要的是流程


过去我们一个jsbridge的开发流程如下:
后来我们增加了三个步骤,让前端更多的参与到其中去,同时每次jsbridge api新增都由专人负责跟进,专门在自测环节去验证一些细节:
    • 两端表现是否统一


    • 异常处理是否合理


    • api设计是否合理


按照专人跟进和前端发挥重要作用的流程走下来,新产出的jsbridge质量明显改善,原因其实很简单:前端最清楚前端希望以什么样的方式调用api。
同时,我们也在逐步沉淀相关的最佳实践,希望对怎样产出一个好的jsbridge api做出详细且权威的解释。
  • 前端标准:从功能开发到使用


    • 功能开发:上文的开发流程标准


    • 文档建设:统一、标准的文档和示例


    • SDK建设:统一、标准的调用方式


    • 调试能力:统一、标准的调试能力


  • 客户端标准:协同标准,主要定义和前端协作相关的


    • 流程标准:上文的开发流程


    • 协议标准:如使用统一的协议开发jsbridge


  • 保证实施


    • 定接口人:前端和客户端两端各出接口人,有问题找接口人。


    • 标准要解决开发痛点:标准首先是解决问题的,然后才是标准,只有解决了开发问题,开发才会乐于接受标准。


    • 标准要不断更新优化:没有任何东西是一成不变的,不断更新优化才能保证有效性。


    • 强制措施还是必须的:没有强制推动的标准很难覆盖全面,故当标准有足够的覆盖率后,需要强制措施保证其全面铺开。


4. 沟通和理解是永远是合作的不二法则

这里的沟通和理解指的前端和客户端开发之间。当然,沟通和理解是相互的,只有单方面的可能效果就差很多。

严选的前端和客户端归属不同的四级部门,因此除了需求之外交集会比较少。在这样的情况下,沟通就变得更为重要了。

4.1 沟通什么
都是开发,有事情带着真诚的、解决问题的态度谈一谈,很多问题都是可以解决的。
  • 专业知识、业务知识、祖传代码,任何能降低职能gap的。
  • 技术方案,模块设计、流程设计、容灾方案,任何能保证需求质量的。
  • 未来规划,有什么想做的,有什么能一起做的,混合开发上,本来就存在大量前端和客户端合作的机会。
  • 当然,任何能建立友好关系的,可惜非我所长,不多加叙述。

4.2 理解什么

前端和客户端都是开发,工作性质都一样,只是客户端因为其发版周期、开发周期等和前端差距较大,看起来似乎存在很大差距。身为开发,相互理解,合作起来会愉快很多:
  • 很多时候客户端的责任会更重,因为出问题APP挂掉可能比一个前端页面挂掉要严重,而且客户端修bug要更麻烦,不像前端能热更新。
  • 都会遇到祖传代码,都会存在年久失修无人维护的逻辑,所以当api调不通有问题时,先彻底排查是否前端的问题,再去找客户端,客户端除了能帮你debug查日志之外,也没有特别多解决问题的办法。
  • 都会想搞点技术项目,所以目标一定要事先对齐,否则临时强插的技术需求很难排上。
  • 做事情都是要老板审批通过的,要干大事当然要先找对方老板。

5. 总结

参与混合开发的前端同学必须要明白,前端是混合开发成果的最终使用者,对开发过程负责,就是对自己负责。所以,不要觉得小题大做,也不要觉得混合开发缺乏技术深度,更多的东西还需要自己去挖掘。希望细节、标准与沟通能在之后的工作中能帮上你的忙。



本文由作者授权严选技术团队发布



您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存